<?php
// +----------------------------------------------------------------------
// | 杭州十禾信息科技有限公司
// +----------------------------------------------------------------------
// | Copyright (c) 2013-2015 http://www.shelpe.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: LeePuman <ysyzlsm@163.com>
// +----------------------------------------------------------------------

class CreativeModel extends NewzanModel{
    
    protected $tableName = 'creatives';
    
    /** @var Model 删除掉的推广组创意. 备份 */
    protected $_deletedMdl = null;
    /** @var Model */
    protected $_logMdl = null;
    /** @var AdgroupModel */
    protected $_adgroupMdl = null;
    
    /** creative log对应的操作  */
    protected $action_names = array(
    		CreativeLogActions::AUTO_ADD => '添加创意',
    		CreativeLogActions::AUTO_DEL => '删除创意',
    		CreativeLogActions::AUTO_UPDATE => '修改创意',
    		CreativeLogActions::MANUAL_ADD => '添加创意',
    		CreativeLogActions::MANUAL_DEL => '删除创意',
    		CreativeLogActions::MANUAL_UPDATE => '修改创意',
    );
    /**
     *  add the creatives to a adgroup SimbaCreativeAddRequest
     *  
     * @param int $user_id 
     * @param int $adgroup_id
     * @param array $creative API请求参数
     * @return null|array 当adgroup不存在, 或者不属于给定的user, 或者已经满2个创意了, 返回null;
     * 	否则返回增加的创意.
     */
    public function addCreative($user_id , $adgroup_id , $creative, $isAutodrive = false){
    	$adgroup = $this->_getAdgroupMdl()->getAdgroupByAdgroupId($user_id, $adgroup_id, false);
    	if(empty($adgroup))
    		throw_exception('给定的推广组不存在.', 'NewzanException', 100);
    	
    	$local_creatives = $this->getCreativesByAdgroupId($user_id, $adgroup_id);
    	if(count($local_creatives) == 4)
    		throw_exception('已经存在4个创意, 不能再添加.', 'NewzanException', 101);
    	
        $creative["adgroup_id"] = $adgroup_id;
        $resp = $this->_api->SimbaCreativeAddRequest( $creative );
        $creative = (array) $resp["creative"];
        
        if($resp) {
	        $creative["user_id"] = $user_id;
            $creative['campaign_id'] = $adgroup['campaign_id'];
            $creative['create_time'] = date('Y-m-d H:i:s', time());
	        
	        // 记录log
	        $this->addLog($creative['creative_id'], $adgroup_id, 
	        		($isAutodrive ? CreativeLogActions::AUTO_ADD : CreativeLogActions::MANUAL_ADD),
	        		json_encode($creative));
	        
	        //add to local storage;
	        $this->add($creative , array() , true);
        }
        return $creative;
    }    
    
    /**
     * 同步一个adgroup的创意
     * 
     * @param int $user_id
     * @param int $adgroup_id
     * @param int $isAutodrive 是否自动开车。如果给定true，那么新增的创意的日志极为“自动”。
     * @return int 返回成功同步的创意个数
     */
    public function syncCreatives($user_id, $adgroup_id, $isAutodrive = false) {
    	if(!$user_id || $adgroup_id <= 0) {
    		throw_exception('参数错误.');
    	}
    	$creative_num = 0; //变化的创意数量
    	$resp = $this->_api->SimbaCreativesGetRequest( array('adgroup_id' => $adgroup_id) );
    	$creatives = $resp['creatives']->creative;
    	$creatives = object_to_array($creatives);
    	$api_creative_ids = array_column($creatives, 'creative_id', false, true);
    	
    	$local_creatives = $this->where(array('user_id' => $user_id, 'adgroup_id' => $adgroup_id))
    			->getField('creative_id,title,img_url,audit_status,audit_desc,modified_time');
    	
    	
    	// delete no-more-existing creatives first
    	if($local_creatives) {
	    	foreach($local_creatives as $creative_id => $local_creative) {
	    		if(!in_array($creative_id, $api_creative_ids)) {
	    			$creative = $this->find($creative_id);
	    			// 备份记录
	    			$this->_getDeletedMdl()->add($creative, array(), true);
	    			// 删除
	    			$this->where( array( "creative_id" => $creative_id , "user_id"=> $user_id ) )->delete();
	    			// 记录log
	    			$this->addLog($creative_id, $adgroup_id, CreativeLogActions::MANUAL_DEL);
	    			
	    			unset($local_creatives[$creative_id]);
	    			
	    			++$creative_num;
	    		}
	    	}
    	}
    	//更新已经存在的creatives
    	foreach($creatives as &$creative){
    		$creative['user_id'] = $user_id;
    		if(!isset($local_creatives[$creative['creative_id']])) {
	    		//saving to local storage
	    		$addRes = $this->add($creative);
	    		
	    		$this->addLog($creative['creative_id'], $adgroup_id,
	    				$isAutodrive ? CreativeLogActions::AUTO_ADD : CreativeLogActions::MANUAL_ADD, 
	    				json_encode($creative));
	    		++$creative_num;
    		} else {
    			$diff = array_kv_diff($local_creatives[$creative['creative_id']], $creative);
    			if($diff) {
	    			$this->addLog($creative['creative_id'], $adgroup_id,
	    					CreativeLogActions::MANUAL_UPDATE, json_encode($diff));
	    			//update the local storage;
	    			$this->where(array('creative_id' => $creative['creative_id']))->save($diff);
	    			++$creative_num;
    			}
    		}
    	}
    	
    	return $creative_num;
    }
    
    public function getCreativeById($user_id, $creative_id, 
    	$fields = 'title,img_url,audit_status,audit_desc,modified_time') {
    	
    	$where = array('user_id' => $user_id, 'creative_id'=>$creative_id);
    	if($fields) {
    		return $this->where($where)->field($fields)->find();
    	} else {
    		return $this->where($where)->find();
    	}
    }
    
    public function getAdgroupId($creative_id) {
    	return $this->where(array('creative_id'=>$creative_id))->getField('adgroup_id');
    }
 
    public function getCreativesByAdgroupId($user_id , $adgroup_id , $useApi = true){
        if(!$adgroup_id){
            throw_exception('参数错误.', 'NewzanException',  RetStatus::PARAM_ERR);
        }
        
        $whr = array( "user_id" => $user_id , "adgroup_id" => $adgroup_id);
        $creatives = $this->where($whr)->select();
        //没有且开了api的情况下，实时获取并同步到数据库
        if( !$creatives  && $useApi ){
                $this->syncCreatives($user_id, $adgroup_id);
                $creatives = $this->where($whr)->select();
        }
        return $creatives;
    }    
    
    public function updateCreative($user_id , $data, $isAutodrive = false, $diff = null){
        //replace the string to api accepet the url
        $resp = $this->_api->SimbaCreativeUpdateRequest($data);
        $creative = (array) $resp["creativerecord"];
        if($creative) {
        	$this->addLog($creative['creative_id'], $data['adgroup_id'], 
        			($isAutodrive ? CreativeLogActions::AUTO_UPDATE : CreativeLogActions::MANUAL_UPDATE), 
        			json_encode($diff ? $diff : $data));
	        //update the local storage;
	        $this->where("creative_id = " . $creative["creative_id"])->save($creative);
        }
        return $creative;
    }
    
    /**
     * delete a creative by  SimbaCreativeDeleteRequest
     * param int ,user_id ,
     * param int , creative_id
     */
    public function deleteCreative($user_id ,$adgroup_id, $creative_id, $isAutodrive = false){
    	$adgroup = $this->_getAdgroupMdl()->getAdgroupByAdgroupId($user_id, $adgroup_id, false);
    	if(empty($adgroup))
    		return false;
    	
    	$resp = $this->_api->SimbaCreativeDeleteRequest( array("creative_id" => $creative_id) );
    	$creative = (array) $resp["creative"];
    	if($creative) {
    		// 备份记录
    		$this->_getDeletedMdl()->add($creative, array(), true);
    		
	    	// 删除
	    	$this->where( array( "creative_id" => $creative_id , "user_id"=> $user_id ) )->delete();
	    	
	    	// 记录log
	    	$this->addLog($creative_id, $creative['adgroup_id'], 
	    			($isAutodrive ? CreativeLogActions::AUTO_DEL : CreativeLogActions::MANUAL_DEL));
    	}
    	return true;
    }
    
    
    /**
     * 添加一条log记录.
     *
     * @see CreativeLogActions
     * @param int $creativeId
     * @param int $adgroupId
     * @param int $action 使用CreativeLogActions::XX常量. 示例: CreativeLogActions::ADD
     * @param string $note 字符串备注. 例如可以给定为关键词修改后的状态json: {max_price: NNN, match_scope: NNN, qscore: NNN}
     * @param string $actTime 格式为'Y-m-d H:i:s'. 动作发生的时间, 留空为当前时刻. 如果是同步时添加的log, 需要给api获取到的时间.
     * @return false|int ThinkkPHP添加记录的返回值. 失败返回false, 否则返回key.
     */
    public function addLog($creativeId, $adgroupId, $action, $note = '', $actTime = null) {
    	$data = array(
    			'creative_id' => $creativeId,
    			'adgroup_id' => $adgroupId,
    			'action' => $action,
    			'note' => $note,
    	);
    	if($actTime) {
    		$data['updated_time'] = $actTime;
    	}
    	return $this->_getLogMdl()->add($data);
    }

    /**
     *
     * 解释一条keyword log
     * @param array(k=>v) $log ， 一条keywords_log中的记录
     * @param bool $simple_disp
     * @return mixed
     */
    public function readLog($log, $simple_disp){
    	$log_detailed = parent::readLog($log, $simple_disp);
    	$note = $log_detailed['action_note'];
    	$log_detailed['action_note'] = $log_detailed['action_name'] . ' [ID: ' . $log['creative_id'] . '] '; 
    	if($log_detailed['action'] == CreativeLogActions::AUTO_UPDATE || CreativeLogActions::MANUAL_UPDATE) {
    		if(isset($note['title'])) {
    			$log_detailed['extra_note'][] = '标题';
    			$log_detailed['extra_note'][] = $note['title'];
    		}
    		if(isset($note['img_url'])) {
    			$log_detailed['extra_note'][] = '图片';
    			$log_detailed['extra_note'][] = $note['img_url'];
    		}
    	}
    	return $log_detailed;
    }
    
     /**
      * @return Model
      */
     protected function _getDeletedMdl() {
     	if($this->_deletedMdl == null) {
     		$this->_deletedMdl = M('creatives_deleted');
     	}
     	return $this->_deletedMdl;
     }
     /**
      * @return Model
      */
     protected function _getLogMdl() {
     	if($this->_logMdl == null) {
     		$this->_logMdl = M('creatives_log');
     	}
     	return $this->_logMdl;
     }
     /**
      * @return AdgroupModel
      */
     protected function _getAdgroupMdl() {
     	if($this->_adgroupMdl == null) {
     		$this->_adgroupMdl = D('Adgroup');
     	}
     	return $this->_adgroupMdl;
     }
     
}

/**
 * 推广计划操作类型常量
 *
 * @author weiping
 */
class CreativeLogActions {
	/** 自动添加 */
	const AUTO_ADD = 0;
	/** 自动删除 */
	const AUTO_DEL = 1;
	/** 自动更新预算 */
	const AUTO_UPDATE = 2;
	
	/** 手动添加 */
	const MANUAL_ADD = 10;
	/** 手动删除 */
	const MANUAL_DEL = 11;
	/** 手动更新预算 */
	const MANUAL_UPDATE = 12;

}
